/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.pm;

import android.content.res.XmlResourceParser;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Printer;

import java.text.Collator;
import java.util.Comparator;

/**
 * 包含包管理器保存的所有包项的公共信息的基类。 这提供了一组非常常见的基本属性：标签，图标和元数据。
 * 本课程不打算单独使用; 只是在这里共享包管理器返回的所有项目之间的通用定义。
 * 因此，它本身并不实现Parcelable，但确实提供了便利的方法来帮助在子类中实现Parcelable。
 *
 */
public class PackageItemInfo {
    /**
     * 这个项目的公开名称。 来自“android：name”属性。
     */
    public String name;
    
    /**
     * 该项目所在的包的名称。
     */
    public String packageName;
    
    /**
     * 此组件标签的字符串资源标识符（位于程序包的资源中）。 从“标签”属性或如果未设置，则为0。
     */
    public int labelRes;
    
    /**
     * AndroidManifest文件中提供的字符串（如果有的话）。 你可能不想使用这个，你可以使用
     * {@link PackageManager#getApplicationLabel}
     */
    public CharSequence nonLocalizedLabel;
    
    /**
     * 此组件图标的可绘制资源标识符（位于程序包的资源中）。 从“图标”属性或如果未设置，则为0。
     */
    public int icon;
    
    /**
     * 该组件横幅的可绘制资源标识符（位于软件包资源中）。 从“banner”属性或者如果未设置，则为0。
     */
    public int banner;

    /**
     * 此组件徽标的可绘制资源标识符（位于程序包的资源中）。 徽标可能比图标更大/更宽，并且由某些UI元素代替名称或名称/图标组合显示。 从“徽标”属性或者如果未设置，则为0。
     */
    public int logo;
    
    /**
     *、与此组件关联的其他元数据。 如果您在请求信息时设置了{@link PackageManager#GET_META_DATA}标志，则只填写该字段。
     */
    public Bundle metaData;

    /**
     *如果不同UserHandle。USER_NULL，这个项目的图标将是那个用户中的一个
     * @hide
     */
    public int showUserIcon;

    public PackageItemInfo() {
        showUserIcon = UserHandle.USER_NULL;
    }

    public PackageItemInfo(PackageItemInfo orig) {
        name = orig.name;
        if (name != null) name = name.trim();
        packageName = orig.packageName;
        labelRes = orig.labelRes;
        nonLocalizedLabel = orig.nonLocalizedLabel;
        if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim();
        icon = orig.icon;
        banner = orig.banner;
        logo = orig.logo;
        metaData = orig.metaData;
        showUserIcon = orig.showUserIcon;
    }

    /**
     *检索与此项目关联的当前文本标签。这将调用给定的PackageManager来从应用程序加载标签。
     * 
     * @param pm 可以装入标签的PackageManager;通常，您最初检索此项目的PackageManager。
     * 
     * @return 返回包含项目标签的CharSequence。如果该项目没有标签，它的名称将返回。
     */
    public CharSequence loadLabel(PackageManager pm) {
        if (nonLocalizedLabel != null) {
            return nonLocalizedLabel;
        }
        if (labelRes != 0) {
            CharSequence label = pm.getText(packageName, labelRes, getApplicationInfo());
            if (label != null) {
                return label.toString().trim();
            }
        }
        if (name != null) {
            return name;
        }
        return packageName;
    }
    
    /**
     *检索与此项目关联的当前图形图标。这将调用给定的PackageManager来从应用程序加载图标。
     * 
     * @param pm 可以加载该图标的PackageManager;通常，您最初检索此项目的PackageManager。
     * 
     * @return 返回包含该项目图标的Drawable。如果该项目没有图标，则返回该项目的默认图标，例如默认活动图标。
     */
    public Drawable loadIcon(PackageManager pm) {
        return pm.loadItemIcon(this, getApplicationInfo());
    }

    /**
     * 检索与此项目相关的当前图形标题。这将调用给定的PackageManager来从应用程序加载横幅。
     *
     * @param pm 可以加载横幅的PackageManager;通常，您最初检索此项目的PackageManager。
     *
     * @return 返回包含项目标题的Drawable。如果该项目没有横幅，此方法将返回null。
     */
    public Drawable loadBanner(PackageManager pm) {
        if (banner != 0) {
            Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
            if (dr != null) {
                return dr;
            }
        }
        return loadDefaultBanner(pm);
    }

    /**
     * 检索与此项目相关的默认图形图标。
     * 
     * @param pm 可从其中加载图标的程序包管理器; 通常是您最初从中检索此项目的包管理器
     * 
     * @return 消除了包含项目的默认图标（如默认活动图标）的Drawable
     * 
     * @hide
     */
    public Drawable loadDefaultIcon(PackageManager pm) {
        return pm.getDefaultActivityIcon();
    }

    /**
     * 检索与此项目关联的默认图形横幅
     *
     * @param pm 可以从中加载横幅的软件包管理器; 通常是您最初从中检索此项目的包管理器。
     *
     * @return 返回包含项目默认标题的Drawable，如果没有默认标识，则返回null。
     *
     * @hide
     */
    protected Drawable loadDefaultBanner(PackageManager pm) {
        return null;
    }

    /**
     *检索与此项目关联的当前图形徽标。 这将回调给定的包管理器从应用程序加载徽标。
     *
     * @param pm 可从中加载徽标的包管理器; 通常是您最初从中检索此项目的包管理器。
     * 
     * @return 返回包含项目徽标的Drawable。 如果该项目没有徽标，则此方法将返回空值。
     */
    public Drawable loadLogo(PackageManager pm) {
        if (logo != 0) {
            Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo());
            if (d != null) {
                return d;
            }
        }
        return loadDefaultLogo(pm);
    }
    
    /**
     * 检索与此项目关联的默认图形徽标。
     * 
     * @param pm 可从中加载徽标的包管理器; 通常是您最初从中检索此项目的包管理器。
     * 
     * @return 返回包含项目默认徽标的Drawable;如果没有默认徽标可用，则返回null。
     * 
     * @hide
     */
    protected Drawable loadDefaultLogo(PackageManager pm) {
        return null;
    }
    
    /**
     * 加载附加到该项目的元数据的XML资源。 这将检索名称元数据条目，并且如果已定义回调给定的包管理器以从应用程序加载其XML文件。
     * 
     * @param pm 一个可以加载XML的包管理器; 通常是您最初从中检索此项目的包管理器。
     * @param name 您想要加载的元日期的名称。
     * 
     * @return 返回一个XmlPullParser，您可以使用它来解析指定为元数据的XML文件。 如果未定义元数据名称或找不到XML资源，则返回null。
     */
    public XmlResourceParser loadXmlMetaData(PackageManager pm, String name) {
        if (metaData != null) {
            int resid = metaData.getInt(name);
            if (resid != 0) {
                return pm.getXml(packageName, resid, getApplicationInfo());
            }
        }
        return null;
    }

    protected void dumpFront(Printer pw, String prefix) {
        if (name != null) {
            pw.println(prefix + "name=" + name);
        }
        pw.println(prefix + "packageName=" + packageName);
        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
            pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
                    + " nonLocalizedLabel=" + nonLocalizedLabel
                    + " icon=0x" + Integer.toHexString(icon)
                    + " banner=0x" + Integer.toHexString(banner));
        }
    }
    
    protected void dumpBack(Printer pw, String prefix) {
        // no back here
    }
    
    public void writeToParcel(Parcel dest, int parcelableFlags) {
        dest.writeString(name);
        dest.writeString(packageName);
        dest.writeInt(labelRes);
        TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags);
        dest.writeInt(icon);
        dest.writeInt(logo);
        dest.writeBundle(metaData);
        dest.writeInt(banner);
        dest.writeInt(showUserIcon);
    }
    
    protected PackageItemInfo(Parcel source) {
        name = source.readString();
        packageName = source.readString();
        labelRes = source.readInt();
        nonLocalizedLabel
                = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
        icon = source.readInt();
        logo = source.readInt();
        metaData = source.readBundle();
        banner = source.readInt();
        showUserIcon = source.readInt();
    }

    /**
     * 获取该项目所属的应用程序的ApplicationInfo，如果可用，则返回null。
     * 
     * @return 返回该项目的ApplicationInfo，如果不知道，则返回null。
     * 
     * @hide
     */
    protected ApplicationInfo getApplicationInfo() {
        return null;
    }

    public static class DisplayNameComparator
            implements Comparator<PackageItemInfo> {
        public DisplayNameComparator(PackageManager pm) {
            mPM = pm;
        }

        public final int compare(PackageItemInfo aa, PackageItemInfo ab) {
            CharSequence  sa = aa.loadLabel(mPM);
            if (sa == null) sa = aa.name;
            CharSequence  sb = ab.loadLabel(mPM);
            if (sb == null) sb = ab.name;
            return sCollator.compare(sa.toString(), sb.toString());
        }

        private final Collator   sCollator = Collator.getInstance();
        private PackageManager   mPM;
    }
}
